package com.iscreen.dbupgrade;

import java.sql.SQLException;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import com.iscreen.utils.constants.Constants;
import com.iscreen.utils.db.connection.DBConnection;
import com.iscreen.utils.db.connection.DBConnectionFactory;
import com.iscreen.utils.exceptions.IScreenException;
import com.iscreen.utils.exceptions.IScreenExceptionCodes;

public class DBUpgrade
{
	private static final String PARAM_CONFIG_PATH = "config.path";
	private static final String CONFIG_FILE_NAME = "dbmanager.properties";
	private static final String LOG_DEFINITION_FILE_NAME = "log4j.xml";

	private static DBUpgrade instance = new DBUpgrade();

	private String configPath;
	private String configFile;
	private DBConnection connection;
	private DBUpgradeFactory factory;

	private final static Logger logger = Logger.getLogger(DBUpgrade.class);

	private DBUpgrade()
	{
	}

	private void initPaths() throws IScreenException
	{
		configPath = System.getProperty(PARAM_CONFIG_PATH);
		if ((configPath == null) || (configPath.trim().length() == 0))
		{
			throw new IScreenException(
					IScreenExceptionCodes.MISSING_CONFIG_PARAM,
					"DBUpgrade Initialization Failed. Missing property: "
							+ PARAM_CONFIG_PATH);
		}
	}

	private void initLogger()
	{
		DOMConfigurator.configureAndWatch(configPath + Constants.FILE_SEPARATOR
				+ LOG_DEFINITION_FILE_NAME);
		logger.debug("Logger initialized.");
	}

	private void initConfigFile()
	{
		configFile = configPath + Constants.FILE_SEPARATOR + CONFIG_FILE_NAME;
	}

	private void initConnection() throws IScreenException
	{
		DBConnectionFactory factory = DBConnectionFactory
				.createFactory(configFile);
		connection = factory.getConnection();
		try
		{
			connection.getConnection().setAutoCommit(true);
		}
		catch (SQLException e)
		{
			throw new IScreenException(
					IScreenExceptionCodes.DB_CONNECTION_ERROR, e);
		}
		logger.debug("Connection initialized.");
	}

	private void initSchema() throws IScreenException
	{
		SchemaInitiliazer schemaInitiliazer = new SchemaInitiliazer();
		schemaInitiliazer.init();
		logger.debug("Schema initialized.");
	}

	private boolean init()
	{
		try
		{
			initPaths();
			initLogger();
			initConfigFile();
			initConnection();
			initFactory();
			initSchema();
		}
		catch (IScreenException e)
		{
			e.log();
			logger.fatal("DBUpgrade failed to initialize.");
			return false;
		}
		return true;
	}

	private void initFactory()
	{
		factory = new DBUpgradeFactory(connection);
	}

	private boolean upgrade()
	{
		UpgradePlan plan = new UpgradePlan();
		try
		{
			plan.execute();
		}
		catch (IScreenException e)
		{
			e.log();
			logger.fatal("DB upgrade plan execution failed.");
			return false;
		}
		return true;
	}

	private void run()
	{
		if (!init())
			return;
		logger.info("DBUpgrage initialized.");

		if (!upgrade())
			return;
	}

	// TODO add logs
	public static void main(String[] args)
	{
		try
		{
			instance.run();
		}
		catch (Throwable t)
		{
			logger.fatal("DBUpgrade failed to run.", t);
		}
	}

	public static DBUpgrade getInstance()
	{
		return instance;
	}

	public DBConnection getConnection()
	{
		return connection;
	}

	public DBUpgradeFactory getFactory()
	{
		return factory;
	}

}
